/**
 * @class   wosh::ThreadPool
 * @brief   
 *
 *
 *
 *
 ****************************************************************************
 * @version $Id: ThreadPool.h 2827 2010-08-02 11:01:48Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_ThreadPool_H__
 #define __WOSH_Core_ThreadPool_H__

 #include <woshDefs.h>
 #include <core/Containers.h>
 #include <core/Reflection.h>
 #include <core/ThreadMethod.h>



namespace wosh {


template <class WORKER_TYPE>
class ThreadPool
{
	WOSH_CLASSNAME(wosh::ThreadPool)

	typedef ListT<WORKER_TYPE*> tThreadMethodList;

	public:

		ThreadPool() {
		 }

		virtual ~ThreadPool() {
			this->threads.clear();
		 }

	public:

		// reentrant
		virtual void addThreadMethod( WORKER_TYPE* worker ) {
			this->threads.transactionBeginWrite();
			this->threads.push_back(worker);
			this->threads.transactionEnd();
		 }

		// reentrant
		void waitApplyState( Thread::THREAD_STATE state, unsigned long timeout = LIMIT_ULONG_MAX ) {
			this->threads.transactionBeginWrite();
			typename ListT<WORKER_TYPE*>::Iterator it;
			const typename ListT<WORKER_TYPE*>::ConstIterator it_end = this->threads.end();
			for ( it=this->threads.begin(); it!=it_end; ++it ) {
				if ( *it == NULL ) continue;
				if ( state == Thread::STATE_RUNNING )
					(*it)->startThread(timeout);
				else if ( state == Thread::STATE_STOPPED )
					(*it)->quitThread(timeout);
				else
					Thread::waitState(static_cast<Thread*>(*it), state, timeout);
			 }
			this->threads.transactionEnd();
		 }

		WORKER_TYPE* waitNextIdle_( unsigned long timeout = LIMIT_ULONG_MAX ) {
			
			if ( timeout != 0 )
				timeout = timeout / 10;
			do {
				typename ListT<WORKER_TYPE*>::ConstIterator it;
				const typename ListT<WORKER_TYPE*>::ConstIterator it_end = this->threads.end();
				for ( it=this->threads.begin(); it!=it_end; ++it ) {
					if ( *it == NULL || !(*it)->isIdle() ) continue;
					return *it;
				 }
				if ( timeout == 0 ) break;
				if ( timeout > 0 )
					--timeout;
				ThreadImpl::sleepForMSec(10);
			 }
			while( timeout != 0 );
			return NULL;
		 }


		template <class PARENT_TYPE>
		WRESULT setWorkersCount( int count, PARENT_TYPE* parent )
		 {
			this->threads.transactionBeginWrite();
			if ( count == (int)this->threads.size() ) {
				;
			 }
			else if ( (int)this->threads.size() < count ) {
				for (int i=(int)this->threads.size();i<count; i++)
					this->threads.push_back( new WORKER_TYPE(parent) );
			 }
			else {
				while ( (int)this->threads.size() != count ) {
					typename ListT<WORKER_TYPE*>::Iterator it;
					const typename ListT<WORKER_TYPE*>::ConstIterator it_end = this->threads.end();
					for ( it=this->threads.begin(); it!=it_end; ) {
						if ( *it == NULL ) continue;
						if ( !(*it)->isIdle() ) continue;
						WRESULT stopped = (*it)->quitThread(10000);
						if ( WFAILED(stopped) ) {
							++it;
							continue;
						 }
						delete *it;
						it = this->threads.getVector().erase(it);
						break;
					 }
				 }
			 }
			this->threads.transactionEnd();
			return WRET_OK;
		 }

		WRESULT setOwnerObject( const Object* parent )
		 {
			this->threads.transactionBeginWrite();
			typename ListT<WORKER_TYPE*>::Iterator it;
			const typename ListT<WORKER_TYPE*>::ConstIterator it_end = this->threads.end();
			for ( it=this->threads.begin(); it!=it_end; ++it ) {
				if ( *it == NULL ) continue;
				(*it)->setOwnerObject(parent);
			 }
			this->threads.transactionEnd();
			return WRET_OK;
		 }

/** @name Getters
 * @{
 ******************************************************************************/
	public:

		const tThreadMethodList& getThreads() const		{ return this->threads; }
		tThreadMethodList& getThreads()					{ return this->threads; }

		// reentrant
		int getThreadCount() const						{ return this->threads.count(); }

		// reentrant
		int getThreadBusyCount() const {
			int count = 0;
			this->threads.transactionBeginRead();
			typename ListT<WORKER_TYPE*>::ConstIterator it;
			const typename ListT<WORKER_TYPE*>::ConstIterator it_end = this->threads.end();
			for ( it=this->threads.begin(); it!=it_end; ++it ) {
				if ( *it == NULL || (*it)->isIdle() ) continue;
				++count;
			 }
			this->threads.transactionEnd();
			return count;
		 }


	protected:
		tThreadMethodList threads;


}; // class def


}; // namespace wosh

#endif //__WOSH_Core_ThreadPool_H__
